/**
 * @file    tcp_server.c
 * @brief   测试两个Linux主机（一个客户端，一个服务器）通过TCP协议通信
 * @author  zyh <2972140442@qq.com>
 * @date    2025-06-26
 * @license GPL-2.0
 * @note    服务器负责将接收到的字符串显示在终端上，本文件为终端程序
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>

// 调试用错误输出宏
#define LOG_ERROR(fmt, ...) \
    fprintf(stderr, "[ERROR] %s:%d (%s): " fmt "\n", \
            __FILE__, __LINE__, __func__, ##__VA_ARGS__)

int main()
{
    // 创建套接字(socket)
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if ( -1 == server_fd )
    {
        LOG_ERROR("semget failed,error: %d, %s\n", errno, strerror(errno));
        exit(errno);
    }


    // 绑定套接字(bind)
    // TCP协议使用下面的数据类型来存储 目标IP 和 目标端口
    struct sockaddr_in server_addr;
    memset( &server_addr, 0, sizeof(server_addr) );
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8081);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);    
    if ( -1 == bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) )
    {
        LOG_ERROR("semget failed,error: %d, %s\n", errno, strerror(errno));
        exit(errno);
    }

    // 监听连接(listen)
    printf("开始监听\n");
    if ( -1 == listen(server_fd, 5) )
    {
        LOG_ERROR("semget failed,error: %d, %s\n", errno, strerror(errno));
        exit(errno);        
    }
    // 接受连接(accept)
    printf("开始连接\n");
    struct sockaddr_in client_addr;
    memset( &client_addr, 0, sizeof(client_addr) );
    int len = sizeof(client_addr);
    int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &len);
    if ( -1 == client_fd )
    {
        LOG_ERROR("semget failed,error: %d, %s\n", errno, strerror(errno));
        exit(errno);        
    }
    printf("连接成功\n");

    // 收发数据(read/write或send/recv)
    char buf[1024];
    while(1)
    {
        memset(buf, 0, sizeof(buf));

        read(client_fd, buf, sizeof(buf));
        printf("%s\n",buf);

    }
    

    // 关闭连接(close)
    close(client_fd);
    close(server_fd);

    return 0;
}